package com.todod.base.module.base.service.devicebase;

import com.todod.base.framework.common.pojo.CommonResult;
import com.todod.base.module.base.controller.admin.dto.ReportDataReq;
import com.todod.base.module.base.controller.admin.dto.ResultData;
import com.todod.base.module.system.api.dict.DictDataApi;
import com.todod.base.module.system.api.dict.dto.DictDataRespDTO;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;

import java.io.*;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import com.todod.base.module.base.controller.admin.devicebase.vo.*;
import com.todod.base.module.base.dal.dataobject.devicebase.DeviceBaseDO;
import com.todod.base.framework.common.pojo.PageResult;
import com.todod.base.framework.common.util.object.BeanUtils;

import com.todod.base.module.base.dal.mysql.devicebase.DeviceBaseMapper;
import org.springframework.web.multipart.MultipartFile;

import static com.todod.base.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.todod.base.module.base.enums.ErrorCodeConstants.*;

/**
 * 仪器型号查看 Service 实现类
 *
 * @author 超管儿
 */
@Slf4j
@Service
@Validated
public class DeviceBaseServiceImpl implements DeviceBaseService {



    @Value("${file.upload.path}")
    private String uploadPath;
    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private DeviceBaseMapper deviceBaseMapper;

    @Override
    public Long createDeviceBase(DeviceBaseSaveReqVO createReqVO) {
        // 插入
        DeviceBaseDO deviceBase = BeanUtils.toBean(createReqVO, DeviceBaseDO.class);
        deviceBase.setState(true);
        deviceBaseMapper.insert(deviceBase);
        // 返回
        return deviceBase.getId();
    }

    @Override
    public void updateDeviceBase(DeviceBaseSaveReqVO updateReqVO) {
        // 校验存在
        validateDeviceBaseExists(updateReqVO.getId());
        // 更新
        DeviceBaseDO updateObj = BeanUtils.toBean(updateReqVO, DeviceBaseDO.class);
        deviceBaseMapper.updateById(updateObj);
    }

    @Override
    public void deleteDeviceBase(Long id) {
        // 校验存在
        validateDeviceBaseExists(id);
        // 删除
        deviceBaseMapper.deleteById(id);
    }

    private void validateDeviceBaseExists(Long id) {
        if (deviceBaseMapper.selectById(id) == null) {
            throw exception(DEVICE_BASE_NOT_EXISTS);
        }
    }

    @Override
    public DeviceBaseDO getDeviceBase(Long id) {
        return deviceBaseMapper.selectById(id);
    }

    @Override
    public PageResult<DeviceBaseDO> getDeviceBasePage(DeviceBasePageReqVO pageReqVO) {
        return deviceBaseMapper.selectPage(pageReqVO);
    }

    //获取仪器型号列表信息
    public List<DeviceBaseDO> getListDevice(DeviceBaseSaveReqVO reqVO){
        return deviceBaseMapper.getListDevice(reqVO);
    }



    /**
     * 下载导入模版
     */
    @Override
    public void problemTemplate(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 定义文件路径
        String path = "file/excel/devicebase.xlsx";

        // 从类路径中获取文件输入流
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);

        // 设置响应内容类型为二进制流
        response.setContentType("application/octet-stream");

        // 设置响应头，指示浏览器将文件作为附件下载，并设置文件名
        // 使用URLEncoder.encode编码文件名，以支持中文字符
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("导入模版.xlsx", "UTF-8"));

        // 获取ServletOutputStream用于写入响应数据
        ServletOutputStream outputStream = response.getOutputStream();

        // 使用Apache POI的XSSFWorkbook加载Excel文件
        try (XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
            // 将Excel工作簿写入输出流
            workbook.write(outputStream);
        } finally {
            // 确保输出流被关闭，释放资源
            if (outputStream != null) {
                outputStream.flush();
                outputStream.close();
            }
        }
    }

    /**
     * 上传导入文件
     */
    @Override
    public ResultData uploadFile(MultipartFile file) throws IOException {
        // 使用Apache POI的XSSFWorkbook类读取上传的Excel文件
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file.getInputStream());
        // 获取Excel的第一个工作表
        XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
        // 获取最后一个行号（从0开始计数）
        int lastRowNum = sheet.getLastRowNum();
        // 如果最后一行号小于1，表示没有数据行
        if (lastRowNum < 1) {
            return ResultData.error("请确保填写数据之后再进行上传");
        }
        // 获取上传文件的原始文件名
        String originalFilename = file.getOriginalFilename();
        log.info("----原始文件名:"+originalFilename);
        // 生成一个新的文件名，使用UUID和原始文件的扩展名
        String newfileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        log.info("----新的文件名:"+newfileName);
        // 构建文件的保存路径
        String abstractPath = uploadPath + "/file/excel" + File.separator + new Date().getTime();
        log.info("----构建文件的保存路径:"+abstractPath);
        // 创建保存目录
        File dir = new File(abstractPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 构建完整的文件路径
        String path = abstractPath + "/" + newfileName;
        log.info("----完整的文件路径:"+path);/*D:\ usr\local\tomcat\ upload\manage\file\excel\1733727982295*/
        try {
            // 将上传的文件输入流复制到指定路径的文件中
            FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(path));
            // 返回成功结果，包含文件路径
            return ResultData.success("ok", path);
        } catch (Exception e) {
            // 打印异常堆栈跟踪
            e.printStackTrace();
            // 返回错误结果
            return ResultData.error("上传文件失败");
        }
    }


    /**
     * 执行导入文件
     */
    @Override
    public ResultData reportDepartment(ReportDataReq reportDataReq) throws IOException {
        // 获取文件URL
        String fileUrl = reportDataReq.getFileUrl();
        log.info("----获取文件URL"+fileUrl);
        // 根据URL创建文件对象
        File file = new File(fileUrl);
        // 检查文件是否存在
        if(!file.exists()){
            return ResultData.error("请确保文件上传成功");
        }
        // 创建文件输入流
        FileInputStream inputStream = new FileInputStream(file);
        // 使用XSSFWorkbook读取Excel文件
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);
        // 获取Excel文件的第一个工作表
        XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
        // 获取工作表中的最后一行的行号
        int lastRowNum = sheet.getLastRowNum();
        // 检查是否有数据
        if (lastRowNum < 1) {
            return ResultData.error("请填写数据之后再上传");
        }
        // 创建数据格式化工具
        DataFormatter formatter = new DataFormatter();
        // 标记是否有错误
        boolean flag = true;
        // 遍历每一行数据，从第2行开始（索引为1）
        for (int i = 1; i <= lastRowNum; i++) {
            StringBuffer stringBuffer = new StringBuffer();
            // 获取当前行
            XSSFRow data = sheet.getRow(i);
            // 跳过空行
            if (data == null) {
                continue;
            }
//            XSSFCell cell1 = data.getCell(0);
//            String cell11 = formatter.formatCellValue(cell1);
//            XSSFCell cell2 = data.getCell(1);
//            String cell22 = formatter.formatCellValue(cell2);
            // 检查第三列数据是否为空
            XSSFCell cell3 = data.getCell(2);
            String cell33 = formatter.formatCellValue(cell3);
            if (cell33 == null || StringUtils.isBlank(cell33) || cell33.equals("") || cell33.isEmpty()) {
                stringBuffer.append("(索引)不能为空");
                flag = false;
            }
            // 如果发现错误，将错误信息写入第9列
            if (stringBuffer.length() > 0) {
                XSSFCell cell = data.createCell(8);
                cell.setCellValue(stringBuffer.toString().substring(0, stringBuffer.length() - 1));
            }
        }
        //进行数据导入
        if(flag){
            for (int j = 1; j <= lastRowNum; j++) {
                XSSFRow data = sheet.getRow(j);

                // 获取每一列的数据并格式化
                String deviceModeCode = formatter.formatCellValue(data.getCell(0));
                String type = formatter.formatCellValue(data.getCell(1));
                String mode = formatter.formatCellValue(data.getCell(2));
                String factoryCode = formatter.formatCellValue(data.getCell(3));
                String remark = formatter.formatCellValue(data.getCell(4));
                String state = formatter.formatCellValue(data.getCell(5));
                String createTime = formatter.formatCellValue(data.getCell(6));
                String protocol = formatter.formatCellValue(data.getCell(7));
                String port = formatter.formatCellValue(data.getCell(8));
                String ip = formatter.formatCellValue(data.getCell(9));


                // 创建数据对象
                DeviceBaseDO deviceBaseDO = new DeviceBaseDO();
                //直接转换部分写入
                deviceBaseDO.setDeviceModeCode(deviceModeCode);
                deviceBaseDO.setMode(mode);
                deviceBaseDO.setRemark(remark);
                if (Objects.equals(state, "TRUE")){
                    deviceBaseDO.setState(true);
                }else {
                    deviceBaseDO.setState(false);
                }
                deviceBaseDO.setPort(port);
                deviceBaseDO.setIp(ip);

                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime createtime = LocalDateTime.parse(createTime,dateTimeFormatter);
                deviceBaseDO.setCreateTime(createtime);

                //字典类型转换部分写入
                CommonResult<DictDataRespDTO> typeDict = dictDataApi.parseDictData("yq_type", type);
                CommonResult<DictDataRespDTO> factoryCodeDict = dictDataApi.parseDictData("factory_code", factoryCode);
                CommonResult<DictDataRespDTO> protocolDict = dictDataApi.parseDictData("xy_type", protocol);
                try {
                    // 检查 deviceTypeDict 的 data 是否为 null  防止空指针异常
                    if (typeDict.getData() != null) {
                        deviceBaseDO.setType(typeDict.getData().getValue());
                    }
                    // 检查 calculMethodDict 的 data 是否为 null  防止空指针异常
                    if (factoryCodeDict.getData() != null) {
                        deviceBaseDO.setFactoryCode(factoryCodeDict.getData().getValue());
                    }
                    // 检查 protocolDict 的 data 是否为 null  防止空指针异常
                    if (protocolDict.getData() != null) {
                        deviceBaseDO.setProtocol(protocolDict.getData().getValue());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 执行插入数据操作
                deviceBaseMapper.insert(deviceBaseDO);
            }
            /*// 执行成功 尝试删除文件
            File uploadedFile = new File(fileUrl);
            if (uploadedFile.exists()) {
                if (uploadedFile.delete()) {
                    log.info("----暂存文件删除成功: " + fileUrl);
                } else {
                    log.error("----暂存文件删除失败: " + fileUrl);
                }
            }*/
            return ResultData.success("ok");
        }
        else {
            // 如果数据不合法，保存错误信息并返回错误结果
            File out = new File(fileUrl);
            FileOutputStream outputStream = new FileOutputStream(out);
            xssfWorkbook.write(outputStream);
            outputStream.close();
            return ResultData.error("导入文件中有数据不合法，请查看错误信息说明", reportDataReq.getFileUrl());
        }
    }
    /**
     * 执行导入文件
     */
    @Override
    public ResultData reportDepartment2(String fileUrl) throws IOException {
        // 获取文件URL
        log.info("----获取文件URL"+fileUrl);
        // 根据URL创建文件对象
        File file = new File(fileUrl);
        // 检查文件是否存在
        if(!file.exists()){
            return ResultData.error("请确保文件上传成功");
        }
        // 创建文件输入流
        FileInputStream inputStream = new FileInputStream(file);
        // 使用XSSFWorkbook读取Excel文件
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);
        // 获取Excel文件的第一个工作表
        XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
        // 获取工作表中的最后一行的行号
        int lastRowNum = sheet.getLastRowNum();
        // 检查是否有数据
        if (lastRowNum < 1) {
            return ResultData.error("请填写数据之后再上传");
        }
        // 创建数据格式化工具
        DataFormatter formatter = new DataFormatter();
        // 标记是否有错误
        boolean flag = true;
        // 遍历每一行数据，从第2行开始（索引为1）
        for (int i = 1; i <= lastRowNum; i++) {
            StringBuffer stringBuffer = new StringBuffer();
            // 获取当前行
            XSSFRow data = sheet.getRow(i);
            // 跳过空行
            if (data == null) {
                continue;
            }
//            XSSFCell cell1 = data.getCell(0);
//            String cell11 = formatter.formatCellValue(cell1);
//            XSSFCell cell2 = data.getCell(1);
//            String cell22 = formatter.formatCellValue(cell2);
            // 检查第三列数据是否为空
            XSSFCell cell3 = data.getCell(2);
            String cell33 = formatter.formatCellValue(cell3);
            if (cell33 == null || StringUtils.isBlank(cell33) || cell33.equals("") || cell33.isEmpty()) {
                stringBuffer.append("(索引)不能为空");
                flag = false;
            }
            // 如果发现错误，将错误信息写入第9列
            if (stringBuffer.length() > 0) {
                XSSFCell cell = data.createCell(8);
                cell.setCellValue(stringBuffer.toString().substring(0, stringBuffer.length() - 1));
            }
        }
        //进行数据导入
        if(flag){
            for (int j = 1; j <= lastRowNum; j++) {
                XSSFRow data = sheet.getRow(j);

                // 获取每一列的数据并格式化
                String deviceModeCode = formatter.formatCellValue(data.getCell(0));
                String type = formatter.formatCellValue(data.getCell(1));
                String mode = formatter.formatCellValue(data.getCell(2));
                String factoryCode = formatter.formatCellValue(data.getCell(3));
                String remark = formatter.formatCellValue(data.getCell(4));
                String state = formatter.formatCellValue(data.getCell(5));
                String createTime = formatter.formatCellValue(data.getCell(6));
                String protocol = formatter.formatCellValue(data.getCell(7));
                String port = formatter.formatCellValue(data.getCell(8));
                String ip = formatter.formatCellValue(data.getCell(9));


                // 创建数据对象
                DeviceBaseDO deviceBaseDO = new DeviceBaseDO();
                //直接转换部分写入
                deviceBaseDO.setDeviceModeCode(deviceModeCode);
                deviceBaseDO.setMode(mode);
                deviceBaseDO.setRemark(remark);
                if (Objects.equals(state, "TRUE")){
                    deviceBaseDO.setState(true);
                }else {
                    deviceBaseDO.setState(false);
                }
                deviceBaseDO.setPort(port);
                deviceBaseDO.setIp(ip);

                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime createtime = LocalDateTime.parse(createTime,dateTimeFormatter);
                deviceBaseDO.setCreateTime(createtime);

                //字典类型转换部分写入
                CommonResult<DictDataRespDTO> typeDict = dictDataApi.parseDictData("yq_type", type);
                CommonResult<DictDataRespDTO> factoryCodeDict = dictDataApi.parseDictData("factory_code", factoryCode);
                CommonResult<DictDataRespDTO> protocolDict = dictDataApi.parseDictData("xy_type", protocol);
                try {
                    // 检查 deviceTypeDict 的 data 是否为 null  防止空指针异常
                    if (typeDict.getData() != null) {
                        deviceBaseDO.setType(typeDict.getData().getValue());
                    }
                    // 检查 calculMethodDict 的 data 是否为 null  防止空指针异常
                    if (factoryCodeDict.getData() != null) {
                        deviceBaseDO.setFactoryCode(factoryCodeDict.getData().getValue());
                    }
                    // 检查 protocolDict 的 data 是否为 null  防止空指针异常
                    if (protocolDict.getData() != null) {
                        deviceBaseDO.setProtocol(protocolDict.getData().getValue());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

                //判断要导入的每一个仪器型号数据在库中是否存在
                if(deviceBaseMapper.isExist(deviceBaseDO)>0){
                    log.error(" 该数据已存在，不执行导入操作  {}", deviceBaseDO);
                }else {
                    // 执行插入数据操作
                    deviceBaseMapper.insert(deviceBaseDO);
                }
//                // 执行插入数据操作
//                deviceBaseMapper.insert(deviceBaseDO);
            }
            /*// 执行成功 尝试删除文件
            File uploadedFile = new File(fileUrl);
            if (uploadedFile.exists()) {
                if (uploadedFile.delete()) {
                    log.info("----暂存文件删除成功: " + fileUrl);
                } else {
                    log.error("----暂存文件删除失败: " + fileUrl);
                }
            }*/
            return ResultData.success("ok");
        }
        else {
            // 如果数据不合法，保存错误信息并返回错误结果
            File out = new File(fileUrl);
            FileOutputStream outputStream = new FileOutputStream(out);
            xssfWorkbook.write(outputStream);
            outputStream.close();
            return ResultData.error("导入文件中有数据不合法，请查看错误信息说明", fileUrl);
        }
    }

    /**
     * 下载导入失败错误报告
     */
    @Override
    public void downloadWrongReport(HttpServletResponse response, String fileUrl) throws IOException {
        File file = new File(fileUrl);  // 根据文件路径创建File对象
        // 打开文件输入流，读取文件内容
        FileInputStream inputStream = new FileInputStream(file);
        // 使用XSSFWorkbook读取Excel文件（xlsx格式）
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream);
        ServletOutputStream outputStream = null;
        try {
            // 设置响应头，允许暴露content-disposition头
            response.setHeader("Access-Control-Expose-Headers", "content-disposition");
            // 设置响应头，防止文件名乱码，指定文件名为“错误报告.xlsx”
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("错误报告.xlsx", "UTF-8"));
            // 设置响应头，指定内容类型为二进制流
            response.setHeader("content-type", "application/octet-stream");
            // 获取输出流，用于向客户端发送文件数据
            outputStream = response.getOutputStream();
            // 将Excel工作簿内容写入输出流
            xssfWorkbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();  // 捕获并打印异常
        } finally {
            // 确保输出流在方法结束前关闭
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}